package bjut.core.scan;

import bjut.core.annotation.Component;
import bjut.core.annotation.Scope;
import bjut.core.bean.BeanDefinition;
import bjut.core.postprocessor.AutowiredAnnotationBeanPostProcessor;
import bjut.core.registry.BeanDefinitionRegistry;
import cn.hutool.core.util.StrUtil;

import java.lang.annotation.Annotation;
import java.util.Set;

/**
 * @Author: zhuzhiming
 * @Date: 2022/6/24 16:04
 */
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider {

    private BeanDefinitionRegistry registry;

    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
        this.registry = registry;
    }

    public void doScan(String... basePackages) {

        for (String basePackage : basePackages) {
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
            for (BeanDefinition beanDefinition : candidates) {
                String scope = resolveBeanScope(beanDefinition);
                if (StrUtil.isNotEmpty(scope)) {
                    beanDefinition.setScope(scope);
                }
                registry.registerBeanDefinition(determineBeanName(beanDefinition), beanDefinition);
            }
        }

        registry.registerBeanDefinition("bjut.springframework.context.annotation.internalAutowiredAnnotationProcessor",new BeanDefinition(AutowiredAnnotationBeanPostProcessor.class));

    }

    private String determineBeanName(BeanDefinition beanDefinition) {

        Class<?> beanClass = beanDefinition.getBeanClass();

        Component component = beanClass.getAnnotation(Component.class);
        String value = component.value();
        if (StrUtil.isEmpty(value)) {
            value = StrUtil.lowerFirst(value);
        }
        return value;
    }

    private String resolveBeanScope(BeanDefinition beanDefinition) {

        Class<?> beanClass = beanDefinition.getBeanClass();
        Scope scope = beanClass.getAnnotation(Scope.class);

        if (null != scope) {
            return scope.value();
        }

        return StrUtil.EMPTY;

    }

}
